/**
 * Licensed under the MIT License
 *
 * Copyright (c) 2010 Alexandre Croiseaux
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */
package marcel.display.gui.buttons
{
	import flash.display.DisplayObjectContainer;
	import flash.display.InteractiveObject;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import marcel.display.View;
	import marcel.utils.DisplayObjectUtils;
	
	/**
	 * A CoreClip having special sensor enhancement designating another sprite to serve as the hit area for the current CoreClip.
	 * @author Alexandre Croiseaux
	 */
	public class CoreButton extends View
	{
		//--------------------------------------------------------------------------
		//
		//  Public vars
		//
		//--------------------------------------------------------------------------
		/**
		 * A sensor already existing on stage
		 */
		public var sensor:Sprite;
		
		
		//--------------------------------------------------------------------------
		//
		//  Constructor
		//
		//--------------------------------------------------------------------------
		/**
		 * Constructs a new SensorBox instance and calls the disableChildren method once.
		 * If the 'sensor' property is not null, meaning a movieclip named 'sensor' has been found on stage, it's used has the current sensor
		 */
		public function CoreButton()
		{
			setSensor(sensor);
			focusRect = false;
			disableChildren();
		}
		
		
		//--------------------------------------------------------------------------
		//
		//  Public methods
		//
		//--------------------------------------------------------------------------
		/**
		 * Designates another sprite to serve as the hit area for the current sprite.
		 * @param	sensorSprite	a sprite to transform in hit area. the alpha is automatically set to 0;
		 */
		public function setSensor(sensorSprite:Sprite):void
		{
			sensor = sensorSprite ? sensorSprite : this;
			init();
		}
		
		/**
		 * Sets all InteractiveObject children (including the current sensor) of the current instance to mouseEnabled = false
		 * and all DisplayObjectContainer children to mouseChildren = false.
		 * This method is called once by the constructor.
		 * If you do not want to disable children mouse interactivity, you must override this method.
		 */
		public function disableChildren():void
		{
			var children:Array = DisplayObjectUtils.getChildren(this, false, InteractiveObject);
			for (var i:uint = 0; i < children.length; i++)
			{
				var child:InteractiveObject = children[i];
				if (child != sensor)
				{
					child.mouseEnabled = false;
					if (child is DisplayObjectContainer && child != sensor.parent) DisplayObjectContainer(child).mouseChildren = false;
				}
			}
		}
		
		/**
		 * Creates a CoreClip instances, draws a rectangle inside it using the current object bounds, sets it as sensor and place it behind other elements.
		 * @param	rect a rectangle instance defining the hit area. If null, the 'getBound()' method is used to get the current clip bounds.
		 * @return the created CoreClip instance.
		 */
		public function createDefaultBound(rect:Rectangle = null):View
		{
			var bounds:Rectangle = rect == null ? getBounds(this) : rect;
			var v:View = new View();
			v.graphics.beginFill(0x00FF00);
			v.graphics.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
			addChildAt(v, 0);
			setSensor(v);
			return v;
		}
		
		/**
		 * Puts the sensor on top, in front of all other elements.
		 * @see #disableChildren
		 */
		public function bringSensorToTop():void
		{
			swapChildren(sensor, getChildAt(numChildren - 1));
		}
		
		/**
		 * Method automatically called when the mouse rolls over the sensor.
		 * The body is empty, so this method should be overriden.
		 */
		public function onOver():void {}
		
		/**
		 * Method automatically called when the mouse rolls out the sensor.
		 * The body is empty, so this method should be overriden.
		 */
		public function onOut():void {}
		
		/**
		 * Method automatically called when the sensor is clicked (mouse released).
		 * The body is empty, so this method should be overriden.
		 */
		public function onClick():void {}
		
		/**
		 * Locks or unlocks the sensor by setting the mouseEnabled property to 'locked' value.
		 * Events are not dispatched anymore.
		 * @param	locked	true if the sensor must be locked, false otherwise.
		 */
		public function lock(locked:Boolean):void { mouseEnabled = !locked; }
		
		/**
		 * Indicates if the current sensor is locked.
		 * @return	true if the sensor is locked, false otherwise.
		 */
		public function isLocked():Boolean { return mouseEnabled; }
		
		/**
		 * Sepcifies the callback function for the click eventr
		 */
		public function set click(callBack:Function):void
		{
			addEventListener(MouseEvent.CLICK, callBack);
		}
		
		/**
		 * Locks or unlocks the sensor rollover effects.
		 * Events are still dispatched, but onOver an onOut methods are not called anymore.
		 * @param	locked	true if the sensor must be locked, false otherwise.
		 */
		public function lockRoll(locked:Boolean):void
		{
			if (locked)
			{
				removeEventListener(MouseEvent.ROLL_OVER, onMouseEvent);
				removeEventListener(MouseEvent.ROLL_OUT, onMouseEvent);
			}
			else
			{
				addEventListener(MouseEvent.ROLL_OVER, onMouseEvent);
				addEventListener(MouseEvent.ROLL_OUT, onMouseEvent);
			}
		}
		
		
		//--------------------------------------------------------------------------
		//
		//  Private methods
		//
		//--------------------------------------------------------------------------
		private function init():void
		{
			if (sensor != this) sensor.alpha = 0;
			buttonMode = true;
			sensor.mouseChildren = false;
			
			addEventListener(MouseEvent.ROLL_OVER, onMouseEvent);
			addEventListener(MouseEvent.ROLL_OUT, onMouseEvent);
			addEventListener(MouseEvent.CLICK, onMouseEvent);
		}
		
		
		//--------------------------------------------------------------------------
		//
		//  Events
		//
		//--------------------------------------------------------------------------
		private function onMouseEvent(evt:MouseEvent):void
		{
			if (!mouseEnabled)
			{
				evt.stopImmediatePropagation();
				return;
			}
			
			switch (evt.type)
			{
				case MouseEvent.ROLL_OVER:
					onOver();
					break;
				case MouseEvent.ROLL_OUT:
					onOut();
					break;
				case MouseEvent.CLICK:
					onClick();
					break;
			}
		}
	}
}